/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2022 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <includes.h>
#include "esp8266.h"
#include "stm32f1xx_it.h"
#include "info.h"
#include "bsp_ds18b20.h"
#include "sui.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* 任务优先级 */
#define START_TASK_PRIO 3         // start
#define WIFIREC_TASK_PRIO 4       // wifi接收信息任务, 用来接收信息
#define WIFIRECONNECT_TASK_PRIO 6 // wifi断开与服务器的连接，重新进行连接
#define ELCREC_TASK_PRIO 10       // 接收用电器的信息
#define GETDATA_TASK_PRIO 12      // 获取信息任务
/* 任务堆栈大小	*/
#define START_STK_SIZE 128        // start
#define WIFIREC_STK_SIZE 64       // wifi接收信息任务, 用来接收信息
#define ELCREC_STK_SIZE 64        // 用电器接收信息任务的堆栈大小
#define GETDATA_STK_SIZE 64       // 获取信息的任务
#define WIFIRECONNECT_STK_SIZE 64 // WIFI重新连接

#define WIFI_SEND_INFO_TIME 1000 // wifi发送信息的时间间隔
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* 任务堆栈 */
CPU_STK START_TASK_STK[START_STK_SIZE];                 // start
CPU_STK WIFIREC_TASK_STK[WIFIREC_STK_SIZE];             // wifi接收信息任务, 用来接收信息
CPU_STK ELCREC_TASK_STK[ELCREC_STK_SIZE];               //
CPU_STK WIFIRECONNECT_TASK_STK[WIFIRECONNECT_STK_SIZE]; // wifi重新连接任务
__align(8) CPU_STK GETDATA_TASK_STK[GETDATA_STK_SIZE];  // 获取温度和烟雾传感器信息的任务

/* 任务控制块 */
OS_TCB Start_TaskTCB;         // start
OS_TCB WifiRec_TaskTCB;       // wifi接收信息任务, 用来接收信息
OS_TCB ElcRec_TaskTCB;        //  用电器接收任务控制块
OS_TCB GetData_TaskTCB;       //  获取信息控制块
OS_TCB WifiReconnect_TaskTCB; //  wifi重新连接服务器

// 标志位
OS_FLAG_GRP Wifi_Disconnect_FLAGS_GRP;                      // wifi断开连接标志位组
OS_FLAG_GRP Esp8266_Get_Info_FLAGS_GRP;                     // wifi获取信息事件标志位组
char get_timeBuf[15] = "\"datetime_1\":\"";                 // 获取时间BUF
char date_buf[50];                                          // 时间缓冲区BUF
char WIFI_DISCONNECT[30] = "CLOSED\r\nWIFI DISCONNECT\r\n"; // wifi 断开连接
char SERVER_DISCONNECT[30] = "CLOSED\r\n";                  // 服务器断开连接
uint8_t uc, ucDs18b20Id[8];
OS_FLAGS esp8266_disconnect_flag = 0;          // esp8266没有连接标志位
OS_FLAGS esp8266_disconnectWifi_flag = 0X01;   // esp8266断开wifi连接标志位
OS_FLAGS esp8266_disconnectServer_flag = 0X02; // esp8266断开服务器连接标志位

OS_FLAGS esp8266_get_info_flag = 0;     // esp8266获取信息标志位
OS_FLAGS esp8266_getServer_flag = 0X01; // esp8266获取服务器信息标志位

// static CPU_STK AppTaskDs18b20Stk[APP_TASK_DS18B20_STK_SIZE];

// 软件定时器

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/*任务函数*/
void start_task(void *p_arg);         // start
void wifiRec_task(void *p_arg);       // wifi接收信息任务, 用来接收信息
void elcRec_task(void *p_arg);        // 用电器接收任务
void getData_task(void *p_arg);       // 获取数据任务
void wifiReconnect_task(void *p_arg); // wifi重新连接任务
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
  /* USER CODE BEGIN 1 */
  OS_ERR err;

  OSInit(&err);

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
  CPU_SR_ALLOC();
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();
  MX_TIM2_Init();
  MX_UART4_Init();
  MX_UART5_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);                           // 使能IDLE中断
  HAL_UART_Receive_DMA(&huart1, USART1_RX_BUF, USART1_MAX_RECV_LEN);     // 开启DMA接收使能
  __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);                           // 使能IDLE中断
  HAL_UART_Receive_DMA(&huart3, USART234_RX_BUF, USART234_MAX_RECV_LEN); // 开启DMA接收使能
  __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);                           // 使能IDLE中断
  HAL_UART_Receive_DMA(&huart2, USART234_RX_BUF, USART234_MAX_RECV_LEN); // 开启DMA接收使能
  __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);                           // 使能IDLE中断
  HAL_UART_Receive_DMA(&huart4, USART234_RX_BUF, USART234_MAX_RECV_LEN); // 开启DMA接收使能
  strcpy(elc1.name, "ELC1");
  strcpy(elc2.name, "ELC2");
  strcpy(elc3.name, "ELC3");
  printf("hello\r\n");
  info_turn_relay(1, 1);
  info_turn_relay(2, 1);
  info_turn_relay(3, 1);
  OS_CRITICAL_ENTER(); // 进入临界区
  // 创建开始任务
  OSTaskCreate((OS_TCB *)&Start_TaskTCB,                          // 任务控制块
               (CPU_CHAR *)"start_task",                          // 任务名字
               (OS_TASK_PTR)start_task,                           // 任务函数
               (void *)0,                                         // 传递给任务的参数
               (OS_PRIO)START_TASK_PRIO,                          // 任务优先级
               (CPU_STK *)&START_TASK_STK[0],                     // 任务堆栈基地址
               (CPU_STK_SIZE)START_STK_SIZE / 10,                 // 任务堆栈大小
               (CPU_STK_SIZE)START_STK_SIZE,                      // 任务堆栈大小
               (OS_MSG_QTY)0,                                     // 任务内部消息队列能够接收的最大消息数目，为0时禁止接收消息
               (OS_TICK)0,                                        // 当使能时间片轮转时的时间片长度，为0为默认长度
               (void *)0,                                         // 用户补充的存储区
               (OS_OPT)OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR, // 任务选项
               (OS_ERR *)&err);                                   // 存放该函数错误时的返回值
  OS_CRITICAL_EXIT();                                             // 退出临界区
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  // 启动多任务系统，控制权交给uC/OS-III
  OSStart(&err);
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/**
 * @brief 开始任务，用于创建其他的任务
 *
 * @param p_arg
 */
void start_task(void *p_arg)
{
  OS_ERR err;
  CPU_SR_ALLOC();
  p_arg = p_arg;

  CPU_Init(); // 初始化CPU模块

#if OS_CFG_STAT_TASK_EN > 0u
  OSStatTaskCPUUsageInit(&err); //统计任务
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了测量中断关闭时间
  CPU_IntDisMeasMaxCurReset();
#endif

#if OS_CFG_SCHED_ROUND_ROBIN_EN //当使用时间片轮转的时候
                                //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍，既1*5=5ms
  OSSchedRoundRobinCfg(DEF_ENABLED, 1, &err);
#endif

  OS_CRITICAL_ENTER(); // 进入临界区

  DS18B20_Init();

  DS18B20_ReadId(ucDs18b20Id); // 读取 DS18B20 的序列号

  // 创建TASK1任务
  OSTaskCreate((OS_TCB *)&WifiRec_TaskTCB,
               (CPU_CHAR *)"wifiRec_task",
               (OS_TASK_PTR)wifiRec_task,
               (void *)0,
               (OS_PRIO)WIFIREC_TASK_PRIO,
               (CPU_STK *)&WIFIREC_TASK_STK[0],
               (CPU_STK_SIZE)WIFIREC_STK_SIZE / 10,
               (CPU_STK_SIZE)WIFIREC_STK_SIZE,
               (OS_MSG_QTY)0,
               (OS_TICK)0,
               (void *)0,
               (OS_OPT)OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR,
               (OS_ERR *)&err);

  OSTaskCreate((OS_TCB *)&ElcRec_TaskTCB,
               (CPU_CHAR *)"elcRec_task",
               (OS_TASK_PTR)elcRec_task,
               (void *)0,
               (OS_PRIO)ELCREC_TASK_PRIO,
               (CPU_STK *)&ELCREC_TASK_STK[0],
               (CPU_STK_SIZE)ELCREC_STK_SIZE / 10,
               (CPU_STK_SIZE)ELCREC_STK_SIZE,
               (OS_MSG_QTY)0,
               (OS_TICK)0,
               (void *)0,
               (OS_OPT)OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR,
               (OS_ERR *)&err);

  OSTaskCreate((OS_TCB *)&GetData_TaskTCB,
               (CPU_CHAR *)"getData_task",
               (OS_TASK_PTR)getData_task,
               (void *)0,
               (OS_PRIO)GETDATA_TASK_PRIO,
               (CPU_STK *)&GETDATA_TASK_STK[0],
               (CPU_STK_SIZE)GETDATA_STK_SIZE / 10,
               (CPU_STK_SIZE)GETDATA_STK_SIZE,
               (OS_MSG_QTY)0,
               (OS_TICK)0,
               (void *)0,
               (OS_OPT)OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR,
               (OS_ERR *)&err);

  OSTaskCreate((OS_TCB *)&WifiReconnect_TaskTCB,
               (CPU_CHAR *)"wifiReconnect_task",
               (OS_TASK_PTR)wifiReconnect_task,
               (void *)0,
               (OS_PRIO)WIFIRECONNECT_TASK_PRIO,
               (CPU_STK *)&WIFIRECONNECT_TASK_STK[0],
               (CPU_STK_SIZE)WIFIRECONNECT_STK_SIZE / 10,
               (CPU_STK_SIZE)WIFIRECONNECT_STK_SIZE,
               (OS_MSG_QTY)0,
               (OS_TICK)0,
               (void *)0,
               (OS_OPT)OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR,
               (OS_ERR *)&err);

  // 创建事件标志组
  OSFlagCreate((OS_FLAG_GRP *)&Wifi_Disconnect_FLAGS_GRP,
               (CPU_CHAR *)"Wifi_Disconnect_FLAGS_GRP",
               esp8266_disconnect_flag, &err);

  OSFlagCreate((OS_FLAG_GRP *)&Esp8266_Get_Info_FLAGS_GRP, "Esp8266_Get_Info_FLAGS_GRP",
               esp8266_get_info_flag, &err);
  // u5_printf("创建任务成功\r\n");
  OS_CRITICAL_EXIT(); // 退出临界区
  printf("正在创建任务1\r\n");
  OSTaskDel(&Start_TaskTCB, &err); // 删除 start_task任务自身
  // 或者
  // OSTaskDel((OS_TCB*)0, &err);  // 0表示删除自身任务
}

/**
 * @brief WIFI接收信息任务函数, 先初始化WIFI，然后wifi接收到额外的信息，任务才会触发，用于处理wifi的任务
 *
 * @param p_arg
 */
void wifiRec_task(void *p_arg)
{
  OS_ERR err;
  p_arg = p_arg;
  printf("task1 create success\r\n");
  esp8266_init(); // esp8266初始化
  printf("task1 create success\r\n");
  for (size_t i = 0; i < 0XFFFF; i++)
  {
    /* code */
  }
  while (1)
  {
    // 等待事件标志组
    // OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, NULL, &err); // 等待接收信息
    OSFlagPend(&Esp8266_Get_Info_FLAGS_GRP,
               esp8266_get_info_flag,
               0, OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_FLAG_SET_ANY,
               NULL, &err);
    u5_printf("我接收到信息了\r\n");
  }
}

/**
 * @brief esp8266重新连接任务函数，用于esp8266断开连接后, 重新连接wifi或者服务器
 *
 * @param p_arg
 */
void wifiReconnect_task(void *p_arg)
{
  OS_ERR err;
  OS_FLAGS flag_temp = 0;
  while (1)
  {
    flag_temp = OSFlagPend(&Wifi_Disconnect_FLAGS_GRP,
                           (OS_FLAGS)(esp8266_disconnectServer_flag | esp8266_disconnectWifi_flag),
                           0,
                           OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_FLAG_SET_ANY, NULL, &err); // 等待标志位
    switch (flag_temp)
    {
    case 0X01:                  // 断开与wifi的连接
      esp8266_reconnect_wifi(); // 重新连接wifi
      break;
    case 0X02:                    // 断开与server的连接
      esp8266_reconnect_server(); // 重新连接server
      break;
    default:
      break;
    }
  }
}

/**
 * @brief 用电器接收任务，每5秒发一次数据出去，每次轮换端口
 *
 * @param p_arg
 */
void elcRec_task(void *p_arg)
{

  OS_ERR err;
  // CPU_SR_ALLOC();
  (void)p_arg;
  printf("hello");

  while (DEF_TRUE)
  {
    printf("hello");
    if (SUI_101A_Get(&huart2, &elc1) == 0) // SUI0101A测量值读取
    {
      CLR_Buf234(); // 清空缓冲区，防止重复引用
      // OS_CRITICAL_ENTER(); //进入临界段，避免串口打印被打断
      printf("FIRST|V:%.5f|I:%.5f|P:%.5f|PF:%.5f|F:%.5f|W:%.5f|\r\n", elc1.voltage, elc1.current, elc1.power, elc1.power_factor, elc1.frequency, elc1.cumulative_power);
      esp8266_send_info(elc1);// 发送信息到服务端
      // printf("SECOND|V:232.74400|I:0.00000|P:0.00000|PF:0.00000|F:33.65600|W:1.17660|\r\n");
      // OS_CRITICAL_EXIT(); //退出临界段
    }
    OSTimeDly(WIFI_SEND_INFO_TIME, OS_OPT_TIME_DLY, &err); //相对性延时1000个时钟节拍（1s）,5s发一次信息
    if (SUI_101A_Get(&huart3, &elc2) == 0) // 设备2的信息读取
    {
      CLR_Buf234(); 
      printf("SECOND|V:%.5f|I:%.5f|P:%.5f|PF:%.5f|F:%.5f|W:%.5f|\r\n", elc2.voltage, elc2.current, elc2.power, elc2.power_factor, elc2.frequency, elc2.cumulative_power);
      esp8266_send_info(elc2); // 发送信息到服务端
    }
    OSTimeDly(WIFI_SEND_INFO_TIME, OS_OPT_TIME_DLY, &err); //相对性延时1000个时钟节拍（1s）
    if (SUI_101A_Get(&huart4, &elc3) == 0)  //设备3的信息读取
    {
      CLR_Buf234();// 清空缓冲区，防止重复引用
      printf("THIRD|V:%.5f|I:%.5f|P:%.5f|PF:%.5f|F:%.5f|W:%.10f|\r\n", elc3.voltage, elc3.current, elc3.power, elc3.power_factor, elc3.frequency, elc3.cumulative_power);
      esp8266_send_info(elc3); // 发送信息到服务端
    }
    OSTimeDly(WIFI_SEND_INFO_TIME, OS_OPT_TIME_DLY, &err); //相对性延时1000个时钟节拍（1s）
  }
}

/**
 * @brief Get the Data task object
 *
 * @param p_arg
 */
void getData_task(void *p_arg)
{
  OS_ERR err;
  (void)p_arg;
  // CPU_SR_ALLOC();

  printf("\r\nDS18B20的序列号是: 0x");
  for (uc = 0; uc < 8; uc++) // 打印 DS18B20 的序列号
    printf("%.2x", ucDs18b20Id[uc]);

  while (1)
  {
    printf("\r\n获取该序列号器件的温度: %.1f\r\n", DS18B20_GetTemp_MatchRom(ucDs18b20Id)); // 打印通过 DS18B20 序列号获取的温度值
    OSTimeDlyHMSM(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, &err);
  }

  // OS_ERR err;
  // while (1)
  // {
  //   while (DS18B20_Init())
  //   {
  //     printf("\r\n no ds18b20 exit \r\n");
  //     //OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
  //   }

  //   printf("\r\n ds18b20 exit \r\n");
  //   printf("hello world\r\n");
  //   OSTimeDlyHMSM(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, &err);
  // }
  // while (1)
  // {
  //   /* code */
  // }
}

/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
